package com.oim.fx.view.pane;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;

import javax.imageio.ImageIO;

import org.apache.commons.lang3.StringUtils;

import com.oim.common.chat.util.CoreContentUtil;
import com.oim.core.business.box.FaceBox;
import com.oim.core.business.box.GroupMemberBox;
import com.oim.core.business.box.PersonalBox;
import com.oim.core.business.box.UserDataBox;
import com.oim.core.business.constant.RemoteConstant;
import com.oim.core.business.controller.ChatController;
import com.oim.core.business.controller.RemoteController;
import com.oim.core.business.manager.ChatManage;
import com.oim.core.business.manager.HeadImageManager;
import com.oim.core.business.manager.ImageManager;
import com.oim.core.business.manager.LastManager;
import com.oim.core.business.manager.PathManager;
import com.oim.core.business.manager.PromptManager;
import com.oim.core.business.manager.RemoteManager;
import com.oim.core.business.manager.SettingManager;
import com.oim.core.business.manager.VideoManager;
import com.oim.core.business.sender.ChatSender;
import com.oim.core.business.sender.GroupSender;
import com.oim.core.business.sender.VideoSender;
import com.oim.core.business.view.ChatListView;
import com.oim.core.common.action.BackAction;
import com.oim.core.common.action.BackInfo;
import com.oim.core.common.component.file.FileHandleInfo;
import com.oim.core.common.component.file.FileInfo;
import com.oim.core.common.util.AppCommonUtil;
import com.oim.fx.common.box.ImageBox;
import com.oim.fx.common.component.IconButton;
import com.oim.fx.common.component.IconPane;
import com.oim.fx.common.component.ScreenShotFrame;
import com.oim.fx.common.util.ContentUtil;
import com.oim.fx.common.util.FaceUtil;
import com.oim.fx.ui.ChatListFrame;
import com.oim.fx.ui.chat.ChatItem;
import com.oim.fx.ui.chat.SimpleHead;
import com.oim.fx.ui.chat.pane.MessageItemLeft;
import com.oim.fx.ui.chat.pane.MessageItemRight;
import com.oim.fx.ui.chat.pane.NodeChatPane;
import com.oim.fx.ui.component.ImageStyleButton;
import com.oim.fx.ui.list.ListRootPanel;
import com.oim.fx.view.UserChatHistoryView;
import com.oim.ui.fx.classics.RequestFrame;
import com.oim.ui.fx.classics.chat.FacePopup;
import com.only.common.lib.util.OnlyJsonUtil;
import com.only.common.result.Info;
import com.only.common.util.OnlyDateUtil;
import com.only.common.util.OnlyFileUtil;
import com.only.fx.common.action.EventAction;
import com.only.general.annotation.parameter.Define;
import com.only.net.action.Back;
import com.only.net.data.action.DataBackAction;
import com.only.net.data.action.DataBackActionAdapter;
import com.onlyxiahui.app.base.AppContext;
import com.onlyxiahui.app.base.view.AbstractView;
import com.onlyxiahui.im.bean.Group;
import com.onlyxiahui.im.bean.GroupMember;
import com.onlyxiahui.im.bean.UserData;
import com.onlyxiahui.im.message.data.chat.Content;
import com.onlyxiahui.im.message.data.chat.ImageValue;
import com.onlyxiahui.im.message.data.chat.Item;
import com.onlyxiahui.im.message.data.chat.Section;
import com.onlyxiahui.im.message.data.chat.history.UserChatHistoryData;
import com.onlyxiahui.oim.face.bean.FaceCategory;
import com.onlyxiahui.oim.face.bean.FaceInfo;

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;

/**
 * 描述：
 *
 * @author XiaHui
 * @date 2015年3月14日 上午11:14:38
 * @version 0.0.1
 */
public class PaneChatListViewImpl extends AbstractView implements ChatListView {

	protected ScreenShotFrame frame = new ScreenShotFrame();
	protected RequestFrame requestRemoteFrame = new RequestFrame();
	protected ChatListFrame chatListFrame = new ChatListFrame();

	protected Map<String, NodeChatPane> chatPanelMap = new ConcurrentHashMap<String, NodeChatPane>();
	protected Map<String, ChatItem> chatItemMap = new ConcurrentHashMap<String, ChatItem>();
	protected ConcurrentSkipListMap<String, ChatItem> itemMap = new ConcurrentSkipListMap<String, ChatItem>();

	protected Map<String, ListRootPanel> groupUserListMap = new ConcurrentHashMap<String, ListRootPanel>();

	protected FileChooser imageFileChooser;
	protected FileChooser fileChooser;

	protected FacePopup facePopup = new FacePopup();

	protected SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSSS");

	ChatItem tempChatItem;
	private long shakeTime = 0;// 记录收到或者发送抖动信息的时间，为了不过于频繁抖动。
	EventAction<FaceInfo> faceSelectAction;
	public PaneChatListViewImpl(AppContext appContext) {
		super(appContext);

		imageFileChooser = new FileChooser();
		imageFileChooser.getExtensionFilters().add(new ExtensionFilter("图片文件", "*.png", "*.jpg", "*.bmp", "*.gif"));

		fileChooser = new FileChooser();
		// fileChooser.getExtensionFilters().add(new ExtensionFilter("文件"));
//		List<FaceInfo> list = faceConfig.createFaceList();
//		facePopup.set("classical", "经典", list);
//		list = faceConfig.emotionList();
//		facePopup.set("emotion", "大表情", list);
		requestRemoteFrame.setTitle("请求远程控制");
		initFace();
		initEvent();
	}
	private void initFace() {
		FaceBox fb = appContext.getBox(FaceBox.class);
		List<FaceCategory> list = fb.getAllFaceCategoryList();
		for (FaceCategory fc : list) {
			set(fc.getId(), fc.getName(), fc.getFaceInfoList());
		}
	}

	private void set(String key, String name, List<FaceInfo> list) {
		List<ImageStyleButton> faceList = new ArrayList<ImageStyleButton>();

		if (null != list && !list.isEmpty()) {
			for (FaceInfo data : list) {
				// String faceKey = data.getKey();
				String normalPath = data.getShowPath();
				String hoverPath = data.getRealPath();
				String text = data.getText();
				double width = data.getWidth();
				double height = data.getHeight();

				double imageWidth = data.getImageWidth();
				double imageHeight = data.getImageHeight();

				Image normalImage = ImageBox.getImageClassPath(normalPath);
				Image hoverImage = ImageBox.getImageClassPath(hoverPath);
				Tooltip tooltip = new Tooltip(text);

				ImageStyleButton button = new ImageStyleButton(normalImage, hoverImage, null);
				button.setTooltip(tooltip);

				if (width > 0 && height > 0) {
					button.setPrefSize(width, height);
					button.setMinSize(width, height);
				}

				if (imageWidth > 0 && imageHeight > 0) {
					button.setImageSize(imageWidth, imageHeight);
				}
				//

				button.setOnAction(a -> {
					facePopup.hide();
					if (null != faceSelectAction) {
						faceSelectAction.execute(data);
					}
				});
				faceList.add(button);
			}
		}
		facePopup.set(key, name, faceList);
	}
	private void initEvent() {
		Platform.runLater(new Runnable() {
			@Override
			public void run() {

			}
		});
	}

	public boolean isShowing() {
		return chatListFrame.isShowing();
	}

	public boolean hasChatItem(String key) {
		return chatItemMap.containsKey(key);
	}

	@Override
	public void setVisible(boolean visible) {
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				if (visible) {
					chatListFrame.show();
					chatListFrame.toFront();
				} else {
					chatListFrame.hide();
				}
			}
		});
	}

	public boolean isGroupChatShowing(String groupId) {
		String key = this.getGroupKey(groupId);
		return chatListFrame.isShowing() && (null != tempChatItem && key.equals(tempChatItem.getAttribute("key")));
	}

	public boolean isUserChatShowing(String userId) {
		String key = this.getUserKey(userId);
		return chatListFrame.isShowing() && (null != tempChatItem && key.equals(tempChatItem.getAttribute("key")));
	}

	public void show(UserData userData) {
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				ChatItem chatItem = getUserChatItem(userData);
				NodeChatPane chatPanel = getUserChatPanel(userData);
				select(chatItem, chatPanel);
				ChatManage chatManage = appContext.getManager(ChatManage.class);
				chatManage.showUserCaht(userData);
			}
		});
	}

	public void show(Group group) {
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				ChatItem chatItem = getGroupChatItem(group);
				NodeChatPane chatPanel = getGroupChatPanel(group);
				select(chatItem, chatPanel);
				ChatManage chatManage = appContext.getManager(ChatManage.class);
				chatManage.showGroupCaht(group);
			}
		});
	}

	private ChatItem getUserChatItem(UserData userData) {
		String key = this.getUserKey(userData.getId());
		ChatItem item = chatItemMap.get(key);
		if (null == item) {
			item = new ChatItem();
			item.addAttribute("key", key);
			chatItemMap.put(key, item);
			item.addCloseAction(new ChatItemCloseEvent(key));
			item.setOnMouseClicked(new ChatItemClickedEvent(key));
		}

		String text = AppCommonUtil.getDefaultShowName(userData);
		item.setText(text);
		HeadImageManager him = appContext.getManager(HeadImageManager.class);
		Image image = him.getUserHeadImage(userData.getId(), userData.getHead(), 40);
		item.setImage(image);
		return item;
	}

	protected NodeChatPane getUserChatPanel(UserData userData) {
		String userId = userData.getId();
		String key = this.getUserKey(userData.getId());
		NodeChatPane item = chatPanelMap.get(key);
		if (null == item) {
			item = new NodeChatPane();
			item.addAttribute("key", key);
			item.addAttribute("userId", userData.getId());
			item.setSendAction(new ChatItemUserSendEvent(key));
			item.setCloseAction(new ChatItemCloseEvent(key));
			item.setOnWriteKeyReleased(e -> {// 回车发送
				if (!e.isShiftDown() && e.getCode() == KeyCode.ENTER) {
					sendUserMessage(key);
					e.consume();
				}
			});

			EventAction<FaceInfo> faceAction = new EventAction<FaceInfo>() {

				NodeChatPane item;

				@Override
				public void execute(FaceInfo value) {
					if (null != value) {
						sendUserFace(userId, item, value);
					}
				}

				EventAction<FaceInfo> set(NodeChatPane item) {
					this.item = item;
					return this;
				}
			}.set(item);

			// 表情按钮
			Image normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_face.png");
			Image hoverImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_face_hover.png");
			Image pressedImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_face_hover.png");
			final IconPane ib = new IconPane(normalImage, hoverImage, pressedImage);
			ib.setOnMouseClicked(new EventHandler<MouseEvent>() {

				@Override
				public void handle(MouseEvent event) {
					faceSelectAction = (faceAction);
					facePopup.show(ib);
				}
			});
			item.addMiddleTool(ib);
			// 发送图片按钮
			normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_sendpic.png");
			hoverImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_sendpic_hover.png");
			pressedImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_sendpic_hover.png");

			IconPane iconButton = new IconPane(normalImage, hoverImage, pressedImage);
			EventHandler<MouseEvent> e = new EventHandler<MouseEvent>() {
				NodeChatPane item;

				@Override
				public void handle(MouseEvent event) {
					String fullPath = getPicture();
					sendUserImage(userId, item, fullPath);
				}

				EventHandler<MouseEvent> set(NodeChatPane item) {
					this.item = item;
					return this;
				}
			}.set(item);
			iconButton.setOnMouseClicked(e);
			item.addMiddleTool(iconButton);

			EventAction<Image> screenShotAction = new EventAction<Image>() {
				NodeChatPane item;

				@Override
				public void execute(Image image) {
					if (null != image) {
						String fullPath = saveImage(item, image);
						sendUserImage(userId, item, fullPath);
					}
				}

				EventAction<Image> set(NodeChatPane item) {
					this.item = item;
					return this;
				}
			}.set(item);
			// 截屏按钮
			normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_cut.png");
			hoverImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_cut.png");
			pressedImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_cut.png");

			iconButton = new IconPane(normalImage, hoverImage, pressedImage);
			iconButton.setOnMouseClicked(new EventHandler<MouseEvent>() {

				@Override
				public void handle(MouseEvent event) {
					frame.setOnImageAction(screenShotAction);
					frame.setVisible(true);
				}
			});
			item.addMiddleTool(iconButton);

			normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_twitter.png");

			iconButton = new IconPane(normalImage);
			item.addMiddleTool(iconButton);

			iconButton.setOnMouseClicked(new EventHandler<MouseEvent>() {

				@Override
				public void handle(MouseEvent event) {
					sendShake(userData.getId());
				}
			});

			normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/GVideoTurnOnVideo.png");

			iconButton = new IconPane(normalImage);
			item.addMiddleTool(iconButton);

			iconButton.setOnMouseClicked(new EventHandler<MouseEvent>() {

				@Override
				public void handle(MouseEvent event) {
					sendVideo(userData);
				}
			});

			normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_register.png");
			hoverImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_register_hover.png");
			pressedImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_register.png");

			iconButton = new IconPane("消息记录", normalImage, hoverImage, pressedImage);
			iconButton.setOnMouseClicked(new EventHandler<MouseEvent>() {

				@Override
				public void handle(MouseEvent event) {
					showChatHistoryView(userData.getId());
					PromptManager pm = appContext.getManager(PromptManager.class);
					pm.remove("offline," + userData.getId());// 系统托盘停止跳动
				}
			});

			item.addMiddleRightTool(iconButton);

			chatPanelMap.put(key, item);
			StackPane rightPane = new StackPane();
			// rightPane.setPrefHeight(350);
			// rightPane.setMaxHeight(350);
			ImageView imageView = new ImageView();
			rightPane.getChildren().add(imageView);

			if (!"2".equals(userData.getGender())) {
				Image image = ImageBox.getImagePath("Resources/Images/Default/Show/default_av_girl_v3.png", 140, 380);
				imageView.setImage(image);
			} else {
				Image image = ImageBox.getImagePath("Resources/Images/Default/Show/default_av_boy_v3.png", 140, 380);
				imageView.setImage(image);
			}
			//item.setRightPane(rightPane);

			Image i = ImageBox.getImageClassPath("/resources/chat/images/user/file/aio_toobar_send_hover.png");

			IconButton isb = new IconButton();
			isb.setNormalImage(i);
			item.addTopTool(isb);

			isb.setOnAction(a -> {
				UserDataBox ub = appContext.getBox(UserDataBox.class);
				boolean online = ub.isOnline(userId);
				if (online) {
					File file = fileChooser.showOpenDialog(chatListFrame);
					if (null != file) {
						SettingManager sm = appContext.getManager(SettingManager.class);
						if (file.length() > sm.getChatSetting().getFileLimitSize()) {
							chatListFrame.showPrompt(sm.getChatSetting().getFileLimitInfo());
							return;
						}
						ChatController cc = appContext.getController(ChatController.class);
						cc.sendFile(userData.getId(), file);
					}
				} else {
					chatListFrame.showPrompt("对方不在线！");
				}
			});

			item.setFileEventAction(file -> {
				if (null != file) {
					UserDataBox ub = appContext.getBox(UserDataBox.class);
					boolean online = ub.isOnline(userId);
					if (online) {
						SettingManager sm = appContext.getManager(SettingManager.class);
						if (file.length() > sm.getChatSetting().getFileLimitSize()) {
							chatListFrame.showPrompt(sm.getChatSetting().getFileLimitInfo());
							return;
						}
						ChatController cc = appContext.getController(ChatController.class);
						cc.sendFile(userData.getId(), file);
					} else {
						chatListFrame.showPrompt("对方不在线！");
					}
				}
			});

			i = ImageBox.getImageClassPath("/resources/chat/images/user/top/Remote_MenuTextue2.png");

			isb = new IconButton();
			isb.setNormalImage(i);
			item.addTopTool(isb);

			isb.setOnAction(a -> {
				UserDataBox ub = appContext.getBox(UserDataBox.class);
				boolean online = ub.isOnline(userId);
				if (online) {
					RemoteController rc = appContext.getController(RemoteController.class);
					rc.requestRemoteControl(userId);
				} else {
					chatListFrame.showPrompt("对方不在线！");
				}
			});
		}

		if (null != userData.getRemarkName() && !"".equals(userData.getRemarkName())) {
			item.setName(userData.getRemarkName());
		} else {
			item.setName(userData.getNickname());
		}
		item.setText(userData.getSignature());
		return item;
	}

	///////////////////////////////////////////////////////// group
	private ChatItem getGroupChatItem(Group group) {
		String key = this.getGroupKey(group.getId());
		ChatItem item = chatItemMap.get(key);
		if (null == item) {
			item = new ChatItem();
			item.addAttribute("key", key);
			chatItemMap.put(key, item);
			item.addCloseAction(new ChatItemCloseEvent(key));
			item.setOnMouseClicked(new ChatItemClickedEvent(key));
		}

		item.setText(group.getName());

		HeadImageManager him = appContext.getManager(HeadImageManager.class);
		Image image = him.getGroupHeadImage(group.getId(), group.getHead());
		item.setImage(image);
		return item;
	}

	protected NodeChatPane getGroupChatPanel(Group group) {
		String groupId = group.getId();
		String key = this.getGroupKey(groupId);
		NodeChatPane item = chatPanelMap.get(key);
		if (null == item) {
			item = new NodeChatPane();
			item.addAttribute("key", key);
			item.addAttribute("groupId", group.getId());
			item.setSendAction(new ChatItemGroupSendEvent(key));
			item.setCloseAction(new ChatItemCloseEvent(key));
			item.setOnWriteKeyReleased(e -> {// 回车发送
				if (!e.isShiftDown() && e.getCode() == KeyCode.ENTER) {
					sendGroupMessage(key);
					e.consume();
				}
			});

			chatPanelMap.put(key, item);
			setGroupUserListPane(item, group.getId());

			EventAction<FaceInfo> faceAction = new EventAction<FaceInfo>() {

				NodeChatPane item;

				@Override
				public void execute(FaceInfo value) {
					if (null != value) {
						sendGroupFace(groupId, item, value);
					}
				}

				EventAction<FaceInfo> set(NodeChatPane item) {
					this.item = item;
					return this;
				}
			}.set(item);

			// 表情按钮
			Image normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_face.png");
			Image hoverImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_face_hover.png");
			Image pressedImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_face_hover.png");
			IconPane ib = new IconPane(normalImage, hoverImage, pressedImage);
			ib.setOnMouseClicked(new EventHandler<MouseEvent>() {

				@Override
				public void handle(MouseEvent event) {
					faceSelectAction = (faceAction);
					facePopup.show(ib);
				}
			});
			item.addMiddleTool(ib);
			// 发送图片按钮
			normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_sendpic.png");
			hoverImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_sendpic_hover.png");
			pressedImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_sendpic_hover.png");

			IconPane iconButton = new IconPane(normalImage, hoverImage, pressedImage);
			EventHandler<MouseEvent> e = new EventHandler<MouseEvent>() {
				NodeChatPane item;

				@Override
				public void handle(MouseEvent event) {
					String fullPath = getPicture();
					sendGroupImage(groupId, item, fullPath);
				}

				EventHandler<MouseEvent> set(NodeChatPane item) {
					this.item = item;
					return this;
				}
			}.set(item);
			iconButton.setOnMouseClicked(e);
			item.addMiddleTool(iconButton);

			EventAction<Image> screenShotAction = new EventAction<Image>() {
				NodeChatPane item;

				@Override
				public void execute(Image image) {
					if (null != image) {
						String fullPath = saveImage(item, image);
						sendGroupImage(groupId, item, fullPath);
					}
				}

				EventAction<Image> set(NodeChatPane item) {
					this.item = item;
					return this;
				}
			}.set(item);
			// 截屏按钮
			normalImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_cut.png");
			hoverImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_cut.png");
			pressedImage = ImageBox.getImageClassPath("/resources/chat/images/middletoolbar/aio_quickbar_cut.png");

			iconButton = new IconPane(normalImage, hoverImage, pressedImage);
			iconButton.setOnMouseClicked(new EventHandler<MouseEvent>() {

				@Override
				public void handle(MouseEvent event) {
					frame.setOnImageAction(screenShotAction);
					frame.setVisible(true);
				}
			});
			item.addMiddleTool(iconButton);

		}
		item.setName(group.getName());
		item.setText(group.getPublicNotice());
		return item;
	}

	//////////////////////////////////////////////////////////
	protected void select(ChatItem item, NodeChatPane chatPanel) {
		if (item != this.tempChatItem) {
			if (null != this.tempChatItem) {
				this.tempChatItem.setSelected(false);
			}
			item.setSelected(true);
		}
		this.tempChatItem = item;
		chatListFrame.addItem(item);
		chatListFrame.setChatPanel(chatPanel);
		if (!itemMap.containsValue(item)) {
			String key = item.getAttribute("key");
			itemMap.put(key, item);
		}
	}

	@Override
	public boolean hasGroupChat(String groupId) {
		String key = getGroupKey(groupId);
		return chatItemMap.containsKey(key);
	}

	@Override
	public boolean hasUserChat(String userId) {
		String key = getUserKey(userId);
		return chatItemMap.containsKey(key);
	}

	protected void sendVideo(UserData userData) {
		PersonalBox pb = appContext.getBox(PersonalBox.class);
		UserData sendUser = pb.getUserData();
		VideoManager vm = this.appContext.getManager(VideoManager.class);
		vm.showSendVideoFrame(userData);
		VideoSender vh = this.appContext.getSender(VideoSender.class);
		vh.requestVideo(sendUser.getId(), userData.getId());
	}

	@Override
	public void userChat(boolean isOwn, UserData userData, Content content) {
		if (null != userData) {
			String name = AppCommonUtil.getDefaultShowName(userData);
			String time = OnlyDateUtil.dateToString(new Date(content.getTimestamp()), "yyyy-MM-dd HH:mm:ss");
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					NodeChatPane chatPanel = getUserChatPanel(userData);
					HeadImageManager him = appContext.getManager(HeadImageManager.class);
					String headPath = him.getUserHeadImagePath(userData.getId(), 40);
					String orientation = isOwn ? "right" : "left";
					insertShow(chatPanel, name, headPath, time, orientation, content); // 143,
				}
			});
		}
	}

	public void groupChat(Group group, UserData userData, Content content) {
		if (null != userData) {
			PersonalBox pb = appContext.getBox(PersonalBox.class);
			UserData user = pb.getUserData();
			boolean isOwn = user.getId().equals(userData.getId());
			String name = AppCommonUtil.getDefaultShowName(userData);
			String time = OnlyDateUtil.getCurrentDateTime();
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					NodeChatPane chatPanel = getGroupChatPanel(group);

					HeadImageManager him = appContext.getManager(HeadImageManager.class);
					String headPath = him.getUserHeadImagePath(userData.getId(), 40);
					String orientation = isOwn ? "right" : "left";
					insertShow(chatPanel, name, headPath, time, orientation, content); // 143,
				}
			});
		}
	}

	protected void insertShow(NodeChatPane cp, String name, String head, String time, String orientation, Content content) {
		if (null != cp) {

			List<Item> items = ContentUtil.getImageItemList(content);
			if (!items.isEmpty()) {

				Map<String, Item> itemMap = new HashMap<String, Item>();
				for (Item item : items) {
					String imageInfo = item.getValue();
					if (null != imageInfo && !"".equals(imageInfo)) {
						if (OnlyJsonUtil.mayBeJSON(imageInfo)) {
							ImageValue iv = OnlyJsonUtil.jsonToObject(imageInfo, ImageValue.class);
							if (null != iv) {
								String id = iv.getId();
								itemMap.put(id, item);
							}
						}
					}
				}

				BackAction<List<FileHandleInfo>> backAction = new BackAction<List<FileHandleInfo>>() {

					@Override
					public void back(BackInfo backInfo, List<FileHandleInfo> list) {
						for (FileHandleInfo info : list) {
							FileInfo fi = info.getFileInfo();
							if (info.isSuccess()) {
								File file = (null != fi) ? fi.getFile() : null;
								String absolutePath = (null != file) ? file.getAbsolutePath() : null;
								String id = (null != fi) ? fi.getId() : "";
								Item item = itemMap.get(id);
								if (null != item && null != absolutePath) {
									item.setValue(absolutePath);
								}
							}
						}
						insertShowPane(cp, name, head, time, orientation, content);
					}
				};
				ImageManager im = this.appContext.getManager(ImageManager.class);
				im.downloadImage(items, backAction);
			} else {
				insertShowPane(cp, name, head, time, orientation, content);
			}
		}
	}

	protected void insertShowPane(NodeChatPane cp, String name, String head, String time, String orientation, Content content) {
		if (null != cp) {

			Image headImage = ImageBox.getImagePath(head, 34, 34, 8, 8);

			boolean left = "left".equals(orientation);
			com.onlyxiahui.im.message.data.chat.Font f = content.getFont();
			Font font = Font.font(f.getName(), FontPosture.ITALIC, f.getSize());
			List<TextFlow> textFlowList = new ArrayList<TextFlow>();

			List<Section> sections = content.getSections();
			if (null != sections) {
				for (Section section : sections) {
					TextFlow textFlow = new TextFlow();

					List<Item> items = section.getItems();
					if (null != items) {
						for (Item item : items) {
							if (Item.type_text.equals(item.getType())) {
								String value = item.getValue();
								Text text = new Text(value);
								text.setFont(font);
								textFlow.getChildren().add(text);
							}
							if (Item.type_face.equals(item.getType())) {
								String faceInfo = item.getValue();
								if (StringUtils.isNotBlank(faceInfo)) {
									String[] array = faceInfo.split(",");
									if (array.length > 1) {
										String categoryId = array[0];
										String value = array[1];
										String fullPath = FaceUtil.getFacePath(categoryId, value);
										if (null != fullPath) {
											Image image = ImageBox.getImagePath(fullPath);
											textFlow.getChildren().add(new ImageView(image));
										}
									}
								}
							}
							if (Item.type_image.equals(item.getType())) {
								String imageInfo = item.getValue();
								if (StringUtils.isNotBlank(imageInfo)) {
									Image image = ImageBox.getImagePath(imageInfo);
									textFlow.getChildren().add(new ImageView(image));
								}
							}
						}
						textFlowList.add(textFlow);
					}
				}
			}
			Platform.runLater(new Runnable() {
				@Override
				public void run() {

					if (left) {
						MessageItemLeft mi = new MessageItemLeft();
						mi.setHeadImage(headImage);
						mi.setTimeText(time);
						mi.setName(name);

						for (TextFlow textFlow : textFlowList) {
							mi.addContentNode(textFlow);
						}
						cp.getMessageList().addNode(mi);

					} else {
						MessageItemRight mi = new MessageItemRight();
						mi.setHeadImage(headImage);
						mi.setName(name);
						mi.setTimeText(time);
						for (TextFlow textFlow : textFlowList) {
							mi.addContentNode(textFlow);
						}
						cp.getMessageList().addNode(mi);
					}
				}
			});
		}
	}

	protected void insertBeforeShow(NodeChatPane cp, String name, String head, String time, String orientation, Content content) {
		if (null != cp) {

			List<Item> items = ContentUtil.getImageItemList(content);
			if (!items.isEmpty()) {

				Map<String, Item> itemMap = new HashMap<String, Item>();
				for (Item item : items) {
					String imageInfo = item.getValue();
					if (null != imageInfo && !"".equals(imageInfo)) {
						if (OnlyJsonUtil.mayBeJSON(imageInfo)) {
							ImageValue iv = OnlyJsonUtil.jsonToObject(imageInfo, ImageValue.class);
							if (null != iv) {
								String id = iv.getId();
								itemMap.put(id, item);
							}
						}
					}
				}

				BackAction<List<FileHandleInfo>> backAction = new BackAction<List<FileHandleInfo>>() {

					@Override
					public void back(BackInfo backInfo, List<FileHandleInfo> list) {
						for (FileHandleInfo info : list) {
							FileInfo fi = info.getFileInfo();
							if (info.isSuccess()) {
								File file = (null != fi) ? fi.getFile() : null;
								String absolutePath = (null != file) ? file.getAbsolutePath() : null;
								String id = (null != fi) ? fi.getId() : "";
								Item item = itemMap.get(id);
								if (null != item && null != absolutePath) {
									item.setValue(absolutePath);
								}
							}
						}
						insertBeforeShowPane(cp, name, head, time, orientation, content);
					}
				};
				ImageManager im = this.appContext.getManager(ImageManager.class);
				im.downloadImage(items, backAction);
			} else {
				insertBeforeShowPane(cp, name, head, time, orientation, content);
			}
		}
	}

	protected void insertBeforeShowPane(NodeChatPane cp, String name, String head, String time, String orientation, Content content) {
		if (null != cp) {

			Image headImage = ImageBox.getImagePath(head, 34, 34, 8, 8);

			boolean left = "left".equals(orientation);
			com.onlyxiahui.im.message.data.chat.Font f = content.getFont();
			Font font = Font.font(f.getName(), FontPosture.ITALIC, f.getSize());
			List<TextFlow> textFlowList = new ArrayList<TextFlow>();

			List<Section> sections = content.getSections();
			if (null != sections) {
				for (Section section : sections) {
					TextFlow textFlow = new TextFlow();

					List<Item> items = section.getItems();
					if (null != items) {
						for (Item item : items) {
							if (Item.type_text.equals(item.getType())) {
								String value = item.getValue();
								Text text = new Text(value);
								text.setFont(font);
								textFlow.getChildren().add(text);
							}
							if (Item.type_face.equals(item.getType())) {
								String faceInfo = item.getValue();
								if (StringUtils.isNotBlank(faceInfo)) {
									String[] array = faceInfo.split(",");
									if (array.length > 1) {
										String categoryId = array[0];
										String value = array[1];
										String fullPath = FaceUtil.getFacePath(categoryId, value);
										if (null != fullPath) {
											Image image = ImageBox.getImagePath(fullPath);
											textFlow.getChildren().add(new ImageView(image));
										}
									}
								}
							}
							if (Item.type_image.equals(item.getType())) {
								String imageInfo = item.getValue();
								if (StringUtils.isNotBlank(imageInfo)) {
									Image image = ImageBox.getImagePath(imageInfo);
									textFlow.getChildren().add(new ImageView(image));
								}
							}
						}
						textFlowList.add(textFlow);
					}
				}
			}
			Platform.runLater(new Runnable() {
				@Override
				public void run() {

					if (left) {
						MessageItemLeft mi = new MessageItemLeft();
						mi.setHeadImage(headImage);
						mi.setTimeText(time);
						mi.setName(name);

						for (TextFlow textFlow : textFlowList) {
							mi.addContentNode(textFlow);
						}
						cp.getMessageList().addNode(0, mi);

					} else {
						MessageItemRight mi = new MessageItemRight();
						mi.setHeadImage(headImage);
						mi.setName(name);
						mi.setTimeText(time);
						for (TextFlow textFlow : textFlowList) {
							mi.addContentNode(textFlow);
						}
						cp.getMessageList().addNode(0, mi);
					}
				}
			});
		}
	}

	protected void sendUserMessage(String key) {
		PersonalBox pb = appContext.getBox(PersonalBox.class);
		UserData sendUser = pb.getUserData();
		NodeChatPane chatPanel = chatPanelMap.get(key);
		if (null != chatPanel) {
			String text = chatPanel.getWriteText();

			if (StringUtils.isNotBlank(text)) {

				chatPanel.initializeWriteHtml();

				Content content = getContent(Item.type_text, text);
				boolean underline = chatPanel.isUnderline();
				boolean bold = chatPanel.isBold();
				String color = chatPanel.getWebColor();
				boolean italic = chatPanel.isItalic();
				String fontName = chatPanel.getFontName();
				int fontSize = chatPanel.getFontSize();

				com.onlyxiahui.im.message.data.chat.Font font = new com.onlyxiahui.im.message.data.chat.Font();
				font.setBold(bold);
				font.setColor(color);
				font.setItalic(italic);
				font.setName(fontName);
				font.setSize(fontSize);
				font.setUnderline(underline);
				content.setFont(font);

				String receiveUserId = chatPanel.getAttribute("userId");

				String name = AppCommonUtil.getDefaultPersonalShowName(sendUser);
				String time = OnlyDateUtil.getCurrentDateTime();

				DataBackActionAdapter action = new DataBackActionAdapter() {
					@Back
					public void back(Info info, @Define("userData") UserData user) {
						if (info.isSuccess()) {
							UserDataBox ub = appContext.getBox(UserDataBox.class);
							UserData userData = ub.getUserData(receiveUserId);
							if (null != userData) {
								LastManager lastManage = appContext.getManager(LastManager.class);
								String text = CoreContentUtil.getText(content);
								lastManage.addOrUpdateLastUserData(userData, text);
							}
						}
					}
				};
				ChatSender ch = appContext.getSender(ChatSender.class);
				ch.sendUserChatMessage(receiveUserId, sendUser.getId(), content, action);
				Platform.runLater(new Runnable() {
					@Override
					public void run() {
						HeadImageManager him = appContext.getManager(HeadImageManager.class);
						String headPath = him.getUserHeadImagePath(sendUser.getId(), 40);
						String orientation = "right";
						insertShow(chatPanel, name, headPath, time, orientation, content);
					}
				});
			}
		}
	}

	private void sendGroupMessage(String key) {
		PersonalBox pb = appContext.getBox(PersonalBox.class);
		UserData user = pb.getUserData();
		NodeChatPane chatPanel = chatPanelMap.get(key);
		if (null != chatPanel) {
			String text = chatPanel.getWriteText();

			boolean underline = chatPanel.isUnderline();
			boolean bold = chatPanel.isBold();
			String color = chatPanel.getWebColor();
			boolean italic = chatPanel.isItalic();
			String fontName = chatPanel.getFontName();
			int fontSize = chatPanel.getFontSize();
			if (StringUtils.isNotBlank(text)) {

				chatPanel.initializeWriteHtml();

				Content content = getContent(Item.type_text, text);
				com.onlyxiahui.im.message.data.chat.Font font = new com.onlyxiahui.im.message.data.chat.Font();
				font.setBold(bold);
				font.setColor(color);
				font.setItalic(italic);
				font.setName(fontName);
				font.setSize(fontSize);
				font.setUnderline(underline);
				content.setFont(font);

				String groupId = chatPanel.getAttribute("groupId");
				ChatSender ch = appContext.getSender(ChatSender.class);
				ch.sendGroupChatMessage(groupId, user.getId(), content);
			}
		}
	}

	protected Content getContent(String type, String text) {
		List<Section> sectionList = new ArrayList<Section>();

		if (Item.type_text.equals(type)) {
			String[] array = text.split("\n");
			for (String a : array) {
				Item item = new Item();
				item.setType(type);
				item.setValue(a);

				List<Item> itemList = new ArrayList<Item>();
				itemList.add(item);

				Section section = new Section();
				section.setItems(itemList);

				sectionList.add(section);
			}
		} else {

			Item item = new Item();
			item.setType(type);
			item.setValue(text);

			List<Item> itemList = new ArrayList<Item>();
			itemList.add(item);

			Section section = new Section();
			section.setItems(itemList);

			sectionList.add(section);
		}

		Content content = new Content();
		content.setSections(sectionList);
		return content;
	}

	private void selectChatItem(String key) {
		ChatItem ci = chatItemMap.get(key);
		NodeChatPane cp = chatPanelMap.get(key);
		if (null != ci && null != cp) {
			select(ci, cp);
		}
	}

	private void removeChatItem(String key) {
		ChatItem item = chatItemMap.get(key);
		if (null != item) {
			chatListFrame.removeItem(item);
			itemMap.remove(key);

			if (itemMap.isEmpty()) {
				setVisible(false);
			} else {
				if (item.isSelected()) {
					Iterator<String> iterator = itemMap.keySet().iterator();
					if (iterator.hasNext()) {
						String nextKey = iterator.next();
						selectChatItem(nextKey);
					}
				}
			}
		}
	}

	protected String getUserKey(String userId) {
		StringBuilder sb = new StringBuilder();
		sb.append("user_");
		sb.append(userId);
		return sb.toString();
	}

	protected String getGroupKey(String groupId) {
		StringBuilder sb = new StringBuilder();
		sb.append("group_");
		sb.append(groupId);
		return sb.toString();
	}

	protected void setGroupUserListPane(NodeChatPane item, String groupId) {
		ListRootPanel groupUserList = groupUserListMap.get(groupId);
		if (null == groupUserList) {
			updateGroupUserList(groupId);
		} else {
			if (null != item) {
				groupUserList.setPrefWidth(140);
				item.setRightPane(groupUserList);
			}
		}
	}

	public void setGroupUserList(final String groupId) {
		GroupMemberBox gmb = appContext.getBox(GroupMemberBox.class);
		List<GroupMember> gml = gmb.getGroupMemberList(groupId);
		if (null == gml) {
			DataBackAction dataBackAction = new DataBackActionAdapter() {
				@Back
				public void back(@Define("userDataList") List<UserData> userDataList, @Define("groupMemberList") List<GroupMember> groupMemberList) {
					setGroupUserList(groupId, userDataList, groupMemberList);
				}
			};
			GroupSender gh = this.appContext.getSender(GroupSender.class);
			gh.getGroupMemberListWithUserDataList(groupId, dataBackAction);
		}
	}

	public void updateGroupUserList(final String groupId) {

		DataBackAction dataBackAction = new DataBackActionAdapter() {

			@Back
			public void back(@Define("userDataList") List<UserData> userDataList, @Define("groupMemberList") List<GroupMember> groupMemberList) {
				setGroupUserList(groupId, userDataList, groupMemberList);
			}
		};
		GroupSender gh = this.appContext.getSender(GroupSender.class);
		gh.getGroupMemberListWithUserDataList(groupId, dataBackAction);
	}

	private void setGroupUserList(String groupId, List<UserData> userDataList, List<GroupMember> groupMemberList) {
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				GroupMemberBox gmb = appContext.getBox(GroupMemberBox.class);
				gmb.putGroupMemberList(groupId, groupMemberList);
				ListRootPanel groupUserList = groupUserListMap.get(groupId);
				if (groupUserList == null) {
					groupUserList = new ListRootPanel();
				}
				groupUserList.clearNode();
				for (UserData userData : userDataList) {
					SimpleHead item = new SimpleHead();

					item.setOnMouseClicked((MouseEvent me) -> {
						if (me.getClickCount() == 2) {
							ChatManage chatManage = appContext.getManager(ChatManage.class);
							chatManage.showCahtFrame(userData);
						}
						me.consume();
					});
					item.setText(userData.getNickname());
					HeadImageManager him = appContext.getManager(HeadImageManager.class);
					Image image = him.getUserHeadImage(userData.getId(), userData.getHead(), 40);
					// Image image =
					// ImageBox.getImagePath("Resources/Images/Head/User/" +
					// userData.getHead() + ".png", 20, 20);
					item.setHeadSize(20);
					item.setHeadRadius(20);
					item.setImage(image);
					item.addAttribute(UserData.class, userData);
					groupUserList.addNode(item);
				}

				String key = getGroupKey(groupId);
				NodeChatPane chatPanel = chatPanelMap.get(key);
				if (null != chatPanel) {
					groupUserList.setPrefWidth(140);
					chatPanel.setRightPane(groupUserList);
				}
			}
		});
	}

	protected class ChatItemGroupSendEvent implements EventHandler<ActionEvent> {

		String key;

		public ChatItemGroupSendEvent(String key) {
			this.key = key;
		}

		@Override
		public void handle(ActionEvent event) {
			sendGroupMessage(key);
		}
	}

	protected class ChatItemUserSendEvent implements EventHandler<ActionEvent> {

		String key;

		public ChatItemUserSendEvent(String key) {
			this.key = key;
		}

		@Override
		public void handle(ActionEvent event) {
			sendUserMessage(key);
		}
	}

	protected class ChatItemCloseEvent implements EventHandler<ActionEvent> {

		String key;

		public ChatItemCloseEvent(String key) {
			this.key = key;
		}

		@Override
		public void handle(ActionEvent event) {
			removeChatItem(key);
		}
	}

	protected class ChatItemClickedEvent implements EventHandler<MouseEvent> {

		String key;

		public ChatItemClickedEvent(String key) {
			this.key = key;
		}

		@Override
		public void handle(MouseEvent event) {
			selectChatItem(key);
		}
	}

	/**
	 * 发送抖动操作
	 *
	 * @Author: XiaHui
	 * @Date: 2016年2月16日
	 * @ModifyUser: XiaHui
	 * @ModifyDate: 2016年2月16日
	 * @param receiveId
	 */
	protected void sendShake(String receiveId) {
		PersonalBox pb = appContext.getBox(PersonalBox.class);
		UserData sendUser = pb.getUserData();
		ChatSender ch = this.appContext.getSender(ChatSender.class);
		ch.sendShake(receiveId, sendUser.getId());// 发送给接受方
		shake();// 自己执行抖动
	}

	@Override
	public void doShake(UserData userData) {
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				ChatItem chatItem = getUserChatItem(userData);
				NodeChatPane chatPanel = getUserChatPanel(userData);
				select(chatItem, chatPanel);
				ChatManage chatManage = appContext.getManager(ChatManage.class);
				chatManage.showUserCaht(userData);
				shake();
			}
		});
	}

	private void shake() {
		if (System.currentTimeMillis() - shakeTime < 3000) {
			return;
		}
		Platform.runLater(new Runnable() {
			@Override
			public void run() {

				Task<Integer> task = new Task<Integer>() {
					@Override
					protected Integer call() throws Exception {
						int iterations = 0;
						for (int i = 0; i < 3; i++) {
							chatListFrame.setX(chatListFrame.getX() + 4);
							chatListFrame.setY(chatListFrame.getY() - 4);
							try {
								Thread.sleep(40);
								chatListFrame.setX(chatListFrame.getX() - 8);
								chatListFrame.setY(chatListFrame.getY());
								Thread.sleep(40);
								chatListFrame.setX(chatListFrame.getX());
								chatListFrame.setY(chatListFrame.getY() + 4);
								Thread.sleep(40);
								chatListFrame.setX(chatListFrame.getX() + 4);
								chatListFrame.setY(chatListFrame.getY());
								Thread.sleep(40);
							} catch (InterruptedException ex) {
								ex.printStackTrace();
							}
						}
						return iterations;
					}
				};

				Thread th = new Thread(task);
				th.setDaemon(true);
				th.start();
			}
		});
		shakeTime = System.currentTimeMillis();
	}

	public String saveImage(NodeChatPane cp, Image image) {
		String fileName = dateFormat.format(new Date()).toString() + ".png";
		PathManager pm = appContext.getManager(PathManager.class);
		String savePath = pm.getScreenshotSavePath();
		String path = savePath + fileName;
		try {
			OnlyFileUtil.checkOrCreateFolder(path);
			File file = new File(path);
			ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);

		} catch (IOException ex) {
		}
		return path;
	}

	public String getPicture() {
		String fullPath = null;
		File file = imageFileChooser.showOpenDialog(chatListFrame);
		if (file != null) {
			if (file.exists()) {
				SettingManager sm = appContext.getManager(SettingManager.class);
				if (file.length() > sm.getChatSetting().getImageLimitSize()) {
					chatListFrame.showPrompt(sm.getChatSetting().getImageLimitInfo());
					return null;
				}
				fullPath = file.getAbsolutePath();
			}
		}
		return fullPath;
	}

	private void sendGroupImage(String groupId, NodeChatPane cp, String imageUrl) {
		if (StringUtils.isBlank(imageUrl)) {
			return;
		}
		if (!imageUrl.startsWith("file")) {
			if (!imageUrl.startsWith("/")) {
				imageUrl = "/" + imageUrl;
			}
			imageUrl = "file:" + imageUrl;
		}
		PersonalBox pb = appContext.getBox(PersonalBox.class);
		String ownerId = pb.getOwnerUserId();
		Content content = getContent(Item.type_image, imageUrl);
		com.onlyxiahui.im.message.data.chat.Font font = new com.onlyxiahui.im.message.data.chat.Font();
		content.setFont(font);
		List<Item> items = ContentUtil.getImageItemList(content);
		ImageManager im = this.appContext.getManager(ImageManager.class);
		BackAction<List<FileHandleInfo>> backAction = new BackAction<List<FileHandleInfo>>() {

			@Override
			public void back(BackInfo backInfo, List<FileHandleInfo> t) {
				ChatSender ch = appContext.getSender(ChatSender.class);
				ch.sendGroupChatMessage(groupId, ownerId, content);
			}
		};
		im.uploadImage(items, backAction);
	}

	protected void sendUserImage(String userId, NodeChatPane cp, String imageUrl) {
		if (StringUtils.isBlank(imageUrl)) {
			return;
		}
		if (!imageUrl.startsWith("file")) {
			if (!imageUrl.startsWith("/")) {
				imageUrl = "/" + imageUrl;
			}
			imageUrl = "file:" + imageUrl;
		}
		PersonalBox pb = appContext.getBox(PersonalBox.class);
		String ownerId = pb.getOwnerUserId();
		Content content = getContent(Item.type_image, imageUrl);
		com.onlyxiahui.im.message.data.chat.Font font = new com.onlyxiahui.im.message.data.chat.Font();
		content.setFont(font);
		String receiveUserId = userId;
		String sendUserId = ownerId;

		DataBackActionAdapter action = new DataBackActionAdapter() {
			@Back
			public void back(Info info, @Define("userData") UserData user) {
				if (info.isSuccess()) {
					UserDataBox ub = appContext.getBox(UserDataBox.class);
					UserData userData = ub.getUserData(receiveUserId);
					if (null != userData) {
						LastManager lastManage = appContext.getManager(LastManager.class);
						String text = CoreContentUtil.getText(content);
						lastManage.addOrUpdateLastUserData(userData, text);
					}
				}
			}
		};

		List<Item> items = ContentUtil.getImageItemList(content);
		ImageManager im = this.appContext.getManager(ImageManager.class);
		BackAction<List<FileHandleInfo>> backAction = new BackAction<List<FileHandleInfo>>() {

			@Override
			public void back(BackInfo backInfo, List<FileHandleInfo> t) {
				ChatSender ch = appContext.getSender(ChatSender.class);
				ch.sendUserChatMessage(receiveUserId, sendUserId, content, action);
				UserData sendUser = pb.getUserData();
				String name = AppCommonUtil.getDefaultPersonalShowName(sendUser);
				String time = OnlyDateUtil.getCurrentDateTime();
				Platform.runLater(new Runnable() {
					@Override
					public void run() {
						HeadImageManager him = appContext.getManager(HeadImageManager.class);
						String headPath = him.getUserHeadImagePath(sendUserId, 40);
						String orientation = "right";
						insertShow(cp, name, headPath, time, orientation, content); // 143,
					}
				});
			}
		};
		im.uploadImage(items, backAction);
	}

	protected void sendUserFace(String userId, NodeChatPane cp, FaceInfo fd) {
		PersonalBox pb = appContext.getBox(PersonalBox.class);
		String ownerId = pb.getOwnerUserId();
		String categoryId = fd.getCategoryId();
		String key = fd.getKey();
		String value = categoryId + "," + key;

		Content content = getContent(Item.type_face, value);
		com.onlyxiahui.im.message.data.chat.Font font = new com.onlyxiahui.im.message.data.chat.Font();
		content.setFont(font);
		String receiveUserId = userId;
		String sendUserId = ownerId;
		ChatSender ch = appContext.getSender(ChatSender.class);

		UserData sendUser = pb.getUserData();
		String name = AppCommonUtil.getDefaultPersonalShowName(sendUser);
		String time = OnlyDateUtil.getCurrentDateTime();

		DataBackActionAdapter action = new DataBackActionAdapter() {
			@Back
			public void back(Info info, @Define("userData") UserData user) {
				if (info.isSuccess()) {
					UserDataBox ub = appContext.getBox(UserDataBox.class);
					UserData userData = ub.getUserData(receiveUserId);
					if (null != userData) {
						LastManager lastManage = appContext.getManager(LastManager.class);
						String text = CoreContentUtil.getText(content);
						lastManage.addOrUpdateLastUserData(userData, text);
					}

					Platform.runLater(new Runnable() {
						@Override
						public void run() {
							HeadImageManager him = appContext.getManager(HeadImageManager.class);
							String headPath = him.getUserHeadImagePath(sendUser.getId(), 40);
							String orientation = "right";
							insertShow(cp, name, headPath, time, orientation, content);
						}
					});
				}
			}
		};
		ch.sendUserChatMessage(receiveUserId, sendUserId, content, action);
	}

	private void sendGroupFace(String groupId, NodeChatPane cp, FaceInfo fd) {

		PersonalBox pb = appContext.getBox(PersonalBox.class);
		String ownerId = pb.getOwnerUserId();
		String categoryId = fd.getCategoryId();
		String key = fd.getKey();
		String value = categoryId + "," + key;

		Content content = getContent(Item.type_face, value);
		com.onlyxiahui.im.message.data.chat.Font font = new com.onlyxiahui.im.message.data.chat.Font();
		content.setFont(font);
		ChatSender ch = appContext.getSender(ChatSender.class);
		ch.sendGroupChatMessage(groupId, ownerId, content);
	}

	///////////////////////////////////
	private Map<String, UserChatHistoryView> chvMap = new ConcurrentHashMap<String, UserChatHistoryView>();

	/**
	 * 显示历史记录
	 *
	 * @param userId
	 */
	public void showChatHistoryView(String userId) {
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				UserChatHistoryView chf = getChatHistoryView(userId);
				chf.setVisible(true);
			}
		});
	}

	public UserChatHistoryView getChatHistoryView(String userId) {

		UserChatHistoryView chv = chvMap.get(userId);
		if (null == chv) {
			chv = appContext.getObject(UserChatHistoryView.class, true);//.getNewView(UserChatHistoryView.class);
			chv.setUserId(userId);
			chvMap.put(userId, chv);
		}
		return chv;
	}

	@Override
	public void userChatHistory(UserData userData, List<UserChatHistoryData> contents) {

		if (null != contents) {

			PersonalBox pb = appContext.getBox(PersonalBox.class);
			UserData user = pb.getUserData();
			int size = contents.size();
			for (int i = size - 1; i >= 0; i--) {
				UserChatHistoryData chd = contents.get(i);
				UserData sendUserData = chd.getSendUserData();
				Content content = chd.getContent();

				String name = AppCommonUtil.getDefaultShowName(sendUserData);
				String time = OnlyDateUtil.dateToDateTime(new Date(content.getTimestamp()));
				boolean isOwn = user.getId().equals(sendUserData.getId());

				NodeChatPane chatPanel = getUserChatPanel(userData);
				HeadImageManager him = appContext.getManager(HeadImageManager.class);
				String headPath = him.getUserHeadImagePath(userData.getId(), 40);
				String orientation = isOwn ? "right" : "left";
				insertBeforeShow(chatPanel, name, headPath, time, orientation, content);
			}
			// for (UserChatHistoryData chd : contents) {
			//
			//
			// }
		}
	}

	@Override
	public boolean hasRequestRemoteControl(String userId) {
		return requestRemoteFrame.isShowing();
	}

	public void showRequestRemoteControl(UserData userData) {
		String userId = userData.getId();
		String name = AppCommonUtil.getDefaultShowName(userData);
		StringBuilder content = new StringBuilder();
		content.append(name);
		content.append(" 请求远程控制你的电脑，接受还是拒绝？");
		requestRemoteFrame.setContent(content.toString());

		RemoteManager rm = appContext.getManager(RemoteManager.class);
		requestRemoteFrame.setOnAcceptAction(a -> {
			requestRemoteFrame.hide();
			rm.responseRemoteControl(userId, RemoteConstant.action_type_agree);
		});
		requestRemoteFrame.setOnRefuseAction(a -> {
			requestRemoteFrame.hide();
			rm.responseRemoteControl(userId, RemoteConstant.action_type_shut);
		});
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				requestRemoteFrame.show();
			}
		});
	}
}
